#include "Logger.h"
using namespace sf::toolsLog;

#include <time.h>
#include <string.h>  // memset
#include <stdexcept> //异常库
#include <stdarg.h>  // 可变参数库

const char *Logger::s_level[] = {
    "debug",
    "info",
    "warn",
    "error",
    "fatal"};

Logger *Logger::m_instance = nullptr;

Logger::Logger() : m_lever(DEBUG), m_max(0), m_len(0)
{
}

Logger::~Logger()
{
    this->close();
}

Logger *Logger::instance()
{
    if (m_instance == nullptr)
    {
        m_instance = new Logger();
    }
    return m_instance;
}

void Logger::open(const string &filename)
{
    this->m_filename = filename;
    this->m_fout.open(filename, ios::app);
    if (this->m_fout.fail())
    {
        throw std::logic_error("open file failed" + filename);
    }
    cout << "open " << filename << " succeed!" << endl;
    this->m_fout.seekp(0, ios::end);
    this->m_len = this->m_fout.tellp();
    cout << "file len:" << this->m_len << endl;
}

void Logger::close()
{
    this->m_fout.close();
}

void Logger::log(Level level, const char *file, int line, const char *format, ...)
{
    if (level < this->m_lever)
    {
        return;
    }

    if (this->m_fout.fail())
    {
        throw logic_error("open file failed" + m_filename);
    }

    time_t ticks = time(NULL);          //获取当前的时间戳
    struct tm *ptm = localtime(&ticks); // 由当前的时间戳 --》时间结构
    char timestamp[32];
    memset(timestamp, 0, sizeof(timestamp));
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", ptm); //按照格式以字符串的形式存储时间

    // 定义日志格式：时间，级别，日志所在文件的名称，文件行号，
    const char *fmt = "%s %s %s:%d";
    int size = snprintf(NULL, 0, fmt, timestamp, s_level[level], file, line);
    if (size > 0)
    {
        char *buffer = new char[size + 1];
        snprintf(buffer, size + 1, fmt, timestamp, s_level[level], file, line);
        buffer[size] = 0;
        m_fout << buffer << " "; //写入到内存
        this->m_len += size;
        cout << buffer << endl;
        delete[] buffer;
    }

    // 支持可变参数的格式化
    va_list arg_ptr;
    va_start(arg_ptr, format);
    size = vsnprintf(NULL, 0, format, arg_ptr);
    va_end(arg_ptr);
    if (size > 0)
    {
        char *content = new char[size + 1];
        va_start(arg_ptr, format);
        vsnprintf(content, size + 1, format, arg_ptr);
        va_end(arg_ptr);
        content[size] = 0;
        m_fout << content; //写入到内存
        this->m_len += size;
        cout << content << endl;
        delete[] content;
    }
    m_fout << "\n";
    m_fout.flush(); //写入到磁盘

    // 日志翻滚
    if(this->m_len >= this->m_max && this->m_max > 0)
    {
        rotate();
    }

    // 测试
    // cout << timestamp << endl;
    // cout << file << endl;
    // cout << line << endl;
    // cout << format << endl;
}

void Logger::level(Level lever)
{
    this->m_lever = lever;
}

void Logger::max(int bytes)
{
    this->m_max = bytes;
}

void Logger::rotate()
{
    this->close();
    time_t ticks = time(NULL);
    struct tm* ptm = localtime(&ticks);
    char timestamp[32];
    memset(timestamp, 0, sizeof(timestamp));
    strftime(timestamp, sizeof(timestamp), ".%Y-%m-%d_%H:%M:%S", ptm);
    string filename = this->m_filename + timestamp;
    if(rename(this->m_filename.c_str(), filename.c_str()) != 0)
    {
        throw logic_error("rename log file failed: " + string(strerror(errno)));
    }
    this->open(this->m_filename);
}
